//********************************************************************
//	created:	15:10:2011   21:56
//	filename: 	socketmanager.h
//	author:		tiamo
//	purpose:	socket manager
//********************************************************************

#pragma once

namespace network
{
	//
	// socket event
	//
	class SocketEvent
	{
	public:
		//
		// event type
		//
		enum
		{
			//
			// invalid
			//
			Invalid,

			//
			// connected
			//
			Connected,

			//
			// closed
			//
			Closed,

			//
			// data packet
			//
			DataPacket,
		};

	public:
		//
		// constructor
		//
		SocketEvent()														{mEventType = Invalid;}

		//
		// constructor
		//
		SocketEvent(uint32_t eventType, utils::SmartPointer<AsyncSocket> const& theSocket, bool errorState);

		//
		// constructor
		//
		SocketEvent(utils::SmartPointer<AsyncSocket> const& theSocket, utils::SmartPointer<BasePacket>&& thePacket);

		//
		// move constructor
		//
		SocketEvent(SocketEvent&& rhs) : mSocket(std::move(rhs.mSocket)), mPacket(std::move(rhs.mPacket)) {mEventType = rhs.mEventType; mErrorState = rhs.mErrorState;}

		//
		// move assignment
		//
		SocketEvent& operator=(SocketEvent&& r)								{if(this != &r){mEventType = r.mEventType; mErrorState = r.mErrorState; mSocket = std::move(r.mSocket); mPacket = std::move(r.mPacket);} return *this;}

		//
		// get event type
		//
		uint32_t getEventType() const										{return mEventType;}

		//
		// get socket
		//
		utils::SmartPointer<AsyncSocket> const& getSocket() const			{return mSocket;}

		//
		// get error state
		//
		bool getErrorState() const											{return mErrorState;}

		//
		// get packet
		//
		utils::SmartPointer<BasePacket> const& getPacket() const			{return mPacket;}

	private:
		//
		// disable copy/assignment
		//
		SocketEvent(SocketEvent const& rhs);
		SocketEvent& operator=(SocketEvent const& rhs);

	private:
		//
		// event type
		//
		uint32_t															mEventType;

		//
		// socket
		//
		utils::SmartPointer<AsyncSocket>									mSocket;

		//
		// error state
		//
		bool																mErrorState;

		//
		// packet
		//
		utils::SmartPointer<BasePacket>										mPacket;
	};

	//
	// socket manager
	//
	class SocketManager : public utils::Thread
	{
	public:
		//
		// constructor
		//
		SocketManager(utils::Event& stopEv) : mStopEvent(stopEv)			{}

		//
		// destructor
		//
		virtual ~SocketManager()											{}

		//
		// start
		//
		virtual void start(utils::Config* config)							{utils::Thread::start();}

		//
		// add socket
		//
		bool addSocket(utils::SmartPointer<AsyncSocket> const& theSocket);

		//
		// close socket
		//
		void closeSocket(utils::SmartPointer<AsyncSocket> const& theSocket, bool errorState);

		//
		// push connected packet
		//
		void pushConnectedPacket(AsyncSocket* theSocket, bool errorState);

		//
		// push data packet
		//
		void pushDataPacket(AsyncSocket* theSocket, utils::SmartPointer<BasePacket>&& dataBuffer);

		//
		// push closed packet
		//
		void pushClosedPacket(AsyncSocket* theSocket, bool errorState);

		//
		// add flush socket
		//
		void addFlushSocket(AsyncSocket* theSocket);

		//
		// process socket event
		//
		void processSocketEvent();

		//
		// close all socket
		//
		void closeAllSocket(bool noEvent);

		//
		// get socket count
		//
		uint32_t getSocketCount()											{utils::Locker lock(mSocketListLock); return static_cast<uint32_t>(mSocketList.size());}

	protected:
		//
		// run
		//
		virtual void run()													{while(!mStopEvent.wait(30)) pollNetworkEvent(0); shutdown();}

		//
		// shutdown
		//
		virtual void shutdown()												{closeAllSocket(true); mSocketEventQueue.clear();}

		//
		// poll network event
		//
		virtual void pollNetworkEvent(uint32_t pollTimeout)					{}

		//
		// add socket
		//
		virtual bool onAddSocket(utils::SmartPointer<AsyncSocket> const&)	{return true;}

		//
		// remove socket
		//
		virtual void onRemoveSocket(utils::SmartPointer<AsyncSocket>const&)	{}

		//
		// remove socket
		//
		bool removeSocket(utils::SmartPointer<AsyncSocket> const& theSocket);

		//
		// network event
		//
		void onNetworkEvent(utils::SmartPointer<AsyncSocket> const& theSocket, bool readEvent, bool writeEvent, bool errorEvent);

		//
		// flush socket buffer
		//
		void flushSocketBuffer();

	protected:
		//
		// max open count
		//
		uint32_t															mMaxOpenCount;

		//
		// socket event queue
		//
		utils::LockedQueue<SocketEvent>										mSocketEventQueue;

		//
		// lock
		//
		utils::Mutex														mSocketListLock;

		//
		// socket list
		//
		std::map<SOCKET, utils::SmartPointer<AsyncSocket>>					mSocketList;

		//
		// flush list lock
		//
		utils::Mutex														mFlushSocketListLock;

		//
		// flush list
		//
		std::map<SOCKET, utils::SmartPointer<AsyncSocket>>					mFlushSocketList;

		//
		// stop event
		//
		utils::Event&														mStopEvent;
	};
}
